package com.etone.eos.handler;

import com.alibaba.fastjson.JSON;
import com.etone.eos.domain.*;
import com.etone.eos.jeos.SmartEosApi;
import com.etone.eos.jeos.SmartEosApiRestClientImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.jafka.jeos.EosApi;
import io.jafka.jeos.EosApiFactory;
import io.jafka.jeos.LocalApi;
import io.jafka.jeos.convert.Packer;
import io.jafka.jeos.core.common.SignArg;
import io.jafka.jeos.core.common.transaction.PackedTransaction;
import io.jafka.jeos.core.common.transaction.TransactionAction;
import io.jafka.jeos.core.common.transaction.TransactionAuthorization;
import io.jafka.jeos.core.request.chain.transaction.PushTransactionRequest;
import io.jafka.jeos.core.request.history.TransactionRequest;
import io.jafka.jeos.core.response.chain.TableRow;
import io.jafka.jeos.core.response.chain.transaction.PushedTransaction;
import io.jafka.jeos.util.KeyUtil;
import io.jafka.jeos.util.Raw;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/***
 * EOS操作工具
 */
@Slf4j
public class EosHandler {
    private String url_chain;
    private String privateKey;

    public EosHandler() {

    }

    public EosHandler(EosConfig eosConfig) {
        url_chain = eosConfig.getUrl_chain();
        privateKey = eosConfig.getPrivateKey();
    }

    /***
     * 执行合约
     * @return
     */
    public PushedTransaction postAction(ActionCreateDTO createArg) throws JsonProcessingException {
        // --- get the current state of blockchain


        EosApi eosApi = EosApiFactory.create(url_chain);
        SignArg arg = eosApi.getSignArg(120);
        System.out.println(eosApi.getObjectMapper().writeValueAsString(arg));
        // --- sign the transation of token tansfer
        String from = createArg.getAccount();
        LocalApi localApi = EosApiFactory.createLocalApi();

        //
        String transferData = eosApi.abiJsonToBin(createArg.getCode(), createArg.getAction(), JSON.toJSON(createArg.getCreateParam())).getBinargs();
        // ③ create the authorization
        List<TransactionAuthorization> authorizations = Arrays.asList(new TransactionAuthorization(from, "active"));

        // ④ build the all actions
        List<TransactionAction> actions = Arrays.asList(//
                new TransactionAction(createArg.getAccount(), createArg.getAction(), authorizations, transferData)//
        );

        // ⑤ build the packed transaction
        PackedTransaction packedTransaction = new PackedTransaction();
        packedTransaction.setExpiration(arg.getHeadBlockTime().plusSeconds(arg.getExpiredSecond()));
        packedTransaction.setRefBlockNum(arg.getLastIrreversibleBlockNum());
        packedTransaction.setRefBlockPrefix(arg.getRefBlockPrefix());

        packedTransaction.setMaxNetUsageWords(0);
        packedTransaction.setMaxCpuUsageMs(0);
        packedTransaction.setDelaySec(0);
        packedTransaction.setActions(actions);

        List<String> sings = sign(privateKey, packedTransaction, arg);
        PushTransactionRequest req = new PushTransactionRequest();
        req.setTransaction(packedTransaction);
        req.setSignatures(sings);

        System.out.println(localApi.getObjectMapper().writeValueAsString(req));

        PushedTransaction pts = eosApi.pushTransaction(req);
        System.out.println(localApi.getObjectMapper().writeValueAsString(pts));
        return pts;
    }

    /***
     * 执行签名
     * @param privateKey
     * @param packedTransaction
     * @param arg
     * @return
     */
    private static List<String> sign(String privateKey, PackedTransaction packedTransaction, SignArg arg) {
        Raw raw = Packer.packPackedTransaction(arg.getChainId(), packedTransaction);
        raw.pack(ByteBuffer.allocate(33).array());// TODO: what's this?
        String hash = KeyUtil.signHash(privateKey, raw.bytes());
        return Arrays.asList(hash);
    }


    /***
     * 获取合约表数据
     */
    public TableRow getTableData(TableParam tableParam) throws JsonProcessingException {
        LocalApi localApi = EosApiFactory.createLocalApi();
        SmartEosApi eosApi = new SmartEosApiRestClientImpl(url_chain);

        TableRow tableRow = eosApi.getSmartTableRows(tableParam.getScope(), tableParam.getCode(), tableParam.getTable(), tableParam.getParams());
        System.out.println(localApi.getObjectMapper().writeValueAsString(tableRow));
        return tableRow;
    }

    /***
     * 查询交易记录
     * @param txId
     * @return
     */
    public TransactionDetail getTransction(String txId) {
        /**
         * {
         * 	"id": "193d38f63c267931b23bbd564f7ed35dda8627dd0c58f9c1a98323be1a984044",
         * 	"trx": {
         * 		"receipt": {
         * 			"status": "executed",
         * 			"cpu_usage_us": 565,
         * 			"net_usage_words": 15,
         * 			"trx": [
         * 				1,
         *                                {
         * 					"compression": "none",
         * 					"prunable_data": {
         * 						"prunable_data": [
         * 							0,
         *                            {
         * 								"signatures": [
         * 									"SIG_K1_Kd9hpjK25pgXCNmdbnZ7r2bzMyvbdHExVbUxBf9gegimSjs7sFcqwcnL4VUKGMmSFLzNKmsmtgphvgqgXQWGpTn7JsRe37"
         * 								],
         * 								"packed_context_free_data": ""
         *                            }
         * 						]
         *                    },
         * 					"packed_trx": "aba33262c87a3df93b2200000000010000000000e0fd7b00000000a86cd445010000000000e0fd7b00000000a8ed32321c0000000000e0fd7b650c0244cf60040005727272723205323232323200"
         *                }
         * 			]
         *        },
         * 		"trx": {
         * 			"expiration": "2022-03-17T02:57:47",
         * 			"ref_block_num": 31432,
         * 			"ref_block_prefix": 574355773,
         * 			"max_net_usage_words": 0,
         * 			"max_cpu_usage_ms": 0,
         * 			"delay_sec": 0,
         * 			"context_free_actions": [],
         * 			"actions": [
         *                {
         * 					"account": "jjyy",
         * 					"name": "create",
         * 					"authorization": [
         *                        {
         * 							"actor": "jjyy",
         * 							"permission": "active"
         *                        }
         * 					],
         * 					"data": {
         * 						"nm": "jjyy",
         * 						"id": "1232343222324325",
         * 						"file_name": "rrrr2",
         * 						"md5": "22222"
         *                    },
         * 					"hex_data": "0000000000e0fd7b650c0244cf600400057272727232053232323232"
         *                }
         * 			],
         * 			"signatures": [
         * 				"SIG_K1_Kd9hpjK25pgXCNmdbnZ7r2bzMyvbdHExVbUxBf9gegimSjs7sFcqwcnL4VUKGMmSFLzNKmsmtgphvgqgXQWGpTn7JsRe37"
         * 			],
         * 			"context_free_data": []
         *        }
         *    },
         * 	"block_time": "2022-03-17T02:57:18.000",
         * 	"block_num": 96970,
         * 	"last_irreversible_block": 96984,
         * 	"traces": [
         *        {
         * 			"action_ordinal": 1,
         * 			"creator_action_ordinal": 0,
         * 			"closest_unnotified_ancestor_action_ordinal": 0,
         * 			"receipt": {
         * 				"receiver": "jjyy",
         * 				"act_digest": "094478ab98475b23af1d0a004a3e189797e20b27051ab2d85a9001134db09cbb",
         * 				"global_sequence": 96987,
         * 				"recv_sequence": 14,
         * 				"auth_sequence": [
         * 					[
         * 						"jjyy",
         * 						17
         * 					]
         * 				],
         * 				"code_sequence": 1,
         * 				"abi_sequence": 1* 			},
         * 			"receiver": "jjyy",
         * 			"act": {
         * 				"account": "jjyy",
         * 				"name": "create",
         * 				"authorization": [
         *                    {
         * 						"actor": "jjyy",
         * 						"permission": "active"
         *                    }
         * 				],
         * 				"data": {
         * 					"nm": "jjyy",
         * 					"id": "1232343222324325",
         * 					"file_name": "rrrr2",
         * 					"md5": "22222"
         *                }                ,
         * 				"hex_data": "0000000000e0fd7b650c0244cf600400057272727232053232323232"
         *            },
         * 			"context_free": false,
         * 			"elapsed": 82,
         * 			"console": "",
         * 			"trx_id": "193d38f63c267931b23bbd564f7ed35dda8627dd0c58f9c1a98323be1a984044",
         * 			"block_num": 96970,
         * 			"block_time": "2022-03-17T02:57:18.000",
         * 			"producer_block_id": null,
         * 			"account_ram_deltas": [
         *                {
         * 					"account": "jjyy",
         * 					"delta": 140
         *                }
         * 			],
         * 			"account_disk_deltas": [],
         * 			"except": null,
         * 			"error_code": null,
         * 			"return_value_hex_data": ""* 		}
         * 	]
         * }
         */
        LocalApi localApi = EosApiFactory.createLocalApi();
        SmartEosApi eosApi = new SmartEosApiRestClientImpl(url_chain);
        TransactionRequest request = new TransactionRequest(txId);
        Object obj = eosApi.getTransaction(request);
        TransactionDetail transactionDetail = JSON.parseObject(obj.toString(), TransactionDetail.class);
//        TransactionDetail.TracesBean.ActBean.DataBeanX dataBeanX = transactionDetail.getTraces().get(0).getAct().getData();
        return transactionDetail;
    }

    public static void main(String[] args) throws JsonProcessingException {
        EosConfig config = new EosConfig();
        ActionCreateDTO createDTO = new ActionCreateDTO();
        createDTO.setAccount("jjyy");
        createDTO.setCode("jjyy");
        createDTO.setAction("create");
        CreateParam param = new CreateParam();
        param.setId(322343242323L);
        param.setFile_name("测试数据");
        param.setNm("jjyy");
        param.setMd5("jfiewjfiwejfiewjfiew");
        createDTO.setCreateParam(param);
        EosHandler handler = new EosHandler(config);
        handler.postAction(createDTO);
        Map<String, String> tableParam = new HashMap<>();
        tableParam.put("lower_bound", "134534525432345");
        tableParam.put("upper_bound", "1345345454232345");
        TableParam tbparam = new TableParam();
        tbparam.setScope("jjyy");
        tbparam.setCode("jjyy");
        tbparam.setTable("cmitfilemd5s");
        tbparam.setParams(tableParam);
        handler.getTableData(tbparam);
    }
}
